
inline vec3::vec3( float x0/* = 0.0f*/, float y0/* = 0.0f*/, float z0/* = 0.0f*/) : 
	x(x0), y(y0), z(z0)
{
	SLMATH_VEC_ASSERT( this->check() );
}

inline vec3::vec3( const vec2& v0, float z0 ) : 
	x(v0.x), y(v0.y), z(z0)
{
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline void vec3::set( float x0, float y0, float z0 )
{
	x=x0;
	y=y0;
	z=z0;
	SLMATH_VEC_ASSERT( (*this).check() );
}

inline vec3& vec3::operator+=( const vec3& o )
{
	x+=o.x;
	y+=o.y;
	z+=o.z;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3& vec3::operator-=( const vec3& o )
{
	x-=o.x;
	y-=o.y;
	z-=o.z;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3& vec3::operator*=( float s )
{
	x*=s;
	y*=s;
	z*=s;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3& vec3::operator*=( const vec3& o )
{
	x *= o.x;
	y *= o.y;
	z *= o.z;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3& vec3::operator/=( const vec3& o )
{
	SLMATH_VEC_ASSERT( fabsf(o.x) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.y) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.z) > FLT_MIN );
	x /= o.x;
	y /= o.y;
	z /= o.z;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3& vec3::operator/=( float s )
{
	SLMATH_VEC_ASSERT( fabsf(s) >= FLT_MIN ); // s must be != 0
	const float sinv = 1.f/s;
	x *= sinv;
	y *= sinv;
	z *= sinv;
	SLMATH_VEC_ASSERT( (*this).check() );
	return *this;
}

inline vec3 vec3::operator/( float s ) const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	SLMATH_VEC_ASSERT( fabsf(s) >= FLT_MIN ); // s must be != 0
	const float sinv = 1.f/s;
	return vec3( x*sinv, y*sinv, z*sinv );
}

inline vec2& vec3::xy()
{
	return *(vec2*)&x;
}

inline vec3 vec3::operator*( const vec3& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec3(x*o.x,y*o.y,z*o.z);
}

inline vec3 vec3::operator/( const vec3& o ) const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	SLMATH_VEC_ASSERT( fabsf(o.x) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.y) > FLT_MIN );
	SLMATH_VEC_ASSERT( fabsf(o.z) > FLT_MIN );
	return vec3(x/o.x,y/o.y,z/o.z);
}

inline vec3 vec3::operator+( const vec3& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec3(x+o.x,y+o.y,z+o.z);
}

inline vec3 vec3::operator-( const vec3& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec3(x-o.x,y-o.y,z-o.z);
}

inline vec3 vec3::operator-() const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec3(-x,-y,-z);
}

inline vec3 vec3::operator*( float s ) const
{
	SLMATH_VEC_ASSERT( slm::check(s) );
	SLMATH_VEC_ASSERT( (*this).check() );
	return vec3(x*s,y*s,z*s);
}

inline bool vec3::operator==( const vec3& o ) const
{
	SLMATH_VEC_ASSERT( o.check() );
	SLMATH_VEC_ASSERT( (*this).check() );
	return x==o.x && y==o.y && z==o.z;
}

inline bool vec3::operator!=( const vec3& o ) const
{
	return !(*this == o);
}

inline const vec2& vec3::xy() const
{
	return *(const vec2*)&x;
}

inline float vec3::dot( const vec3& a)const
{
	SLMATH_VEC_ASSERT( a.check() );
	SLMATH_VEC_ASSERT( (*this).check() );

	float res = a.x*x + a.y*y + a.z*z;

	SLMATH_VEC_ASSERT( res >= -FLT_MAX && res <= FLT_MAX );
	return res;
}

inline vec3 vec3::cross( const vec3& a)const
{
	vec3 res( y*a.z-z*a.y, z*a.x-x*a.z, x*a.y-y*a.x );
	return res;
}

inline float vec3::length()const
{
	float res = sqrtf(lengthSq());
	SLMATH_VEC_ASSERT( res >= 0.f && res <= FLT_MAX );
	return res;
}

inline float vec3::lengthSq()const
{
	SLMATH_VEC_ASSERT( (*this).check() );
	float res = x*x + y*y + z*z;

	SLMATH_VEC_ASSERT( res >= 0.f && res <= FLT_MAX );
	return res;
}

inline float vec3::distance(const vec3& p1 )const
{
	return (*this - p1).length();
}

inline float vec3::distanceSq(const vec3& p1 )const
{
	return (*this - p1).lengthSq();
}

inline vec3 vec3::clamp(const vec3& min, const vec3& max )const
{
	return slm::vecClamp(*this, min, max );
}

inline vec3 vec3::saturate()const
{
	return slm::vecSaturate(*this);
}

inline vec3 vec3::abs()const
{
	return vec3( fabsf(_v[0]), fabsf(_v[1]), fabsf(_v[2]) );
}

inline vec3 vec3::neg()const
{
	return -*this;
}


inline bool vec3::check()const
{
	return x<=FLT_MAX && x>=-FLT_MAX && y<=FLT_MAX && y>=-FLT_MAX && z<=FLT_MAX && z>=-FLT_MAX;
}


inline vec3 vec3::add( const vec3& a)const
{
	return a * (*this);
}

inline vec3 vec3::sub( const vec3& a)const
{
	return *this - a;
}

inline vec3 vec3::mix(const vec3& v, float a)const
{
	return vecMix(*this, v, a);
}

#ifdef SLMATH_AUTO_DX_CONVERSION
inline vec3& vec3::operator = (const D3DXVECTOR3& dxv3)
{
	this->x = dxv3.x;
	this->y = dxv3.y;
	this->z = dxv3.z;
	return *this;
}

inline vec3::operator D3DXVECTOR3()const
{
	return D3DXVECTOR3(x, y, z);
}
#endif // SLMATH_AUTO_DX_CONVERSION

inline vec3 max( const vec3& a, const vec3& b )
{
	return vec3( max(a[0],b[0]), max(a[1],b[1]), max(a[2],b[2]) );
}

inline vec3 min( const vec3& a, const vec3& b )
{
	return vec3( min(a[0],b[0]), min(a[1],b[1]), min(a[2],b[2]) );
}

inline std::ostream& operator << (std::ostream& stream, const vec3& v)
{
	stream << "vec3(" << v.x << "," << v.y << "," << v.z << ")";
	return stream;
}

inline std::wostream& operator << (std::wostream& stream, const vec3& v)
{
	stream << L"vec3(" << v.x << L"," << v.y << L"," << v.z << L")";
	return stream;
}

inline vec3 operator*(float fv, const vec3& v3)
{
	return v3.mul(fv);
}

inline bool check( const vec3& v )
{
	return v.check();
}

// This file is part of 'slm' C++ library. Copyright (C) 2009 Jani Kajala (kajala@gmail.com). See http://sourceforge.net/projects/slm/
